#include "tcp_server.h"
#include "t_thread.h"
#include "../util/timer.h"

void t_Sleep(uint32 seconds)
{
	struct timespec ts, rmts;
	
	ts.tv_sec = seconds/1000;
	ts.tv_nsec = (seconds%1000)*1000000;
	while(1)
	{
		int ret = nanosleep(&ts, &rmts);
		if(ret == 0) 
		{
			break;
		}

		int sleepErr = errno;
		if(ret == -1 && sleepErr == EINTR)
		{
			ts = rmts;
		}
	}
}

tcp_thread::tcp_thread(tcp_sink* sink)
{
	func_lock s_lock;
	m_log = new logfile("tcp_thread");
	m_sink = sink;
	m_single = new epoll_single(20);
	InitThread(false);
	m_log->WriteTrace("thread start");
};

tcp_thread::~tcp_thread()
{
	func_lock s_lock;
   delete m_log;
   StopThread();
   delete m_single;
   m_sink  = NULL;
   m_log->WriteTrace("thread stop");
};

bool tcp_thread::del_socket(uint32 socket)
{
	func_lock s_lock;
     if(m_single->del(socket) == false)
     {
		char lle[1023] = {0};
		sprintf(lle,"delete epoll socket=%d",socket);
		m_log->WriteTrace(lle);
     }

	 return true;
};

bool tcp_thread::add_port(t_socket_server* tcp,uint16 port)
{
	func_lock s_lock;
	std::map<uint16, t_socket_server*>::iterator iter;
	iter = m_portmap.find(port);

	if(iter !=m_portmap.end())
	   return false;
	
	m_single->set(tcp->get_socket(),EPOLLIN | EPOLLHUP | EPOLLERR | EPOLLET);
	m_portmap.insert(std::map<uint32, t_socket_server*>::value_type
		(port,tcp));

	return true;
};

bool tcp_thread::del_port(uint32 port)
{
	func_lock s_lock;
   	std::map<uint16, t_socket_server*>::iterator iter;
	iter = m_portmap.find(port);

	if(iter !=m_portmap.end())
	   return false;

    m_single->del(iter->second->get_socket());
    m_portmap.erase(iter);
	return true;
}

bool tcp_thread::is_new_socket(uint32 socket)
{
	func_lock s_lock;
	bool rt = false;
	std::map<uint16, t_socket_server*>::iterator iter = m_portmap.begin();
	
	while(iter != m_portmap.end())
	{
		if(socket == iter->second->get_socket())
		{
			uint32 newfd = 0;
			sockaddr sock_in;
			memset(&sock_in,0,sizeof(sockaddr));
			while (iter->second->accept_scoket(&newfd,&sock_in)== true)
			{	

				if(newfd == -1)
					break;
				
				uint32 time = get_time();

				m_sink->OnAccept(newfd,sock_in,iter->first);

				char lle[1023] = {0};
				sprintf(lle,"accpet end time=%d,time=%d,socket=%d",
					get_time() -time,get_time(),newfd);
				m_log->WriteTrace(lle);
								
				m_single->set(newfd,EPOLLIN | EPOLLHUP | EPOLLERR | EPOLLET );
				rt = true;
			}
		}
        
		iter++;
	}

	return rt;
}
   
void tcp_thread::Execute()
{
	printf("tcp_thread is run\r\n");
	int count;
	uint32 m_count=0;
	epoll_event events[20];
	char  buf[64* 1024];
	int   buf_size =0;
	bool   bool_recv = false;

	while(!m_finished)
	{
		count = m_single->wait(events);
    	
		m_count++;
		
		if(m_count % 5000 == 0)
		{
			char tt[1024] = {0};
			sprintf(tt,"m_count=%d,time=%d",m_count,get_time());
			m_log->WriteTrace(tt);
		}
		
		for(uint32 i=0; i<count; i++)
		{
			if(is_new_socket(events[i].data.fd) == true)
				continue;

			memset(buf,0,64*1024);
			buf_size = 64 * 1024;

			std::map<uint16, t_socket_server*>::iterator iter = m_portmap.begin();

			uint32 recv = get_time();
			int size = 1;

			while(size != 0)
			{
				size = iter->second->recvbuf(events[i].data.fd,buf,buf_size);

				if(size == -1)
				{
					char ll[1024] = {0};
					sprintf(ll,"server close,socket=%d",events[i].data.fd);
					m_log->WriteTrace(ll);
					m_sink->OnError(events[i].data.fd);
					break;
				}

				if(size == 0)
					break;
				
				uint32 time = get_time();

				m_sink->OnRead(events[i].data.fd,buf,size);
				char lle[1023] = {0};
				sprintf(lle," OnRead time=%d,time=%d,size=%d,socket=%d",
					get_time() -time,get_time(),size,events[i].data.fd);
				m_log->WriteTrace(lle);
			}
		}
        
		uint32 time = get_time();

		m_sink->OnSend();

		if(get_time() -time > 0)
		{
			char lle[1023] = {0};
			sprintf(lle,"On send time=%d,time=%d",
				get_time() -time,get_time());
			//m_log->WriteTrace(lle);
		}
	}
 
	m_log->WriteTrace("exit");
	return;
};
